home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d939.lha / ExtraCmds / source_etc.lha / src / DirTree.c < prev    next >
C/C++ Source or Header  |  1993-10-22  |  10KB  |  404 lines

  1. /*   ---------------------------------      -------     
  2.  *   |\  | | | | |  |.| |   \|  |/ /|\      |||||||     
  3.  *   | | | |/  | |\ |/  |/|  |\ |/  |    ?  ---+---  =< 
  4.  *   | | | |   | |  |     |  |  |   |     \qqqqqqqqq/   
  5.  *   ---------------------------------  ~~~~~~~~~~~~~~~~
  6.  *  DirTree - Prints sub-directory trees
  7.  *  Copyright (C) 1992, 1993 Torsten Poulin
  8.  *
  9.  *  This program is free software; you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License as published by
  11.  *  the Free Software Foundation; either version 2 of the License, or
  12.  *  (at your option) any later version.
  13.  *
  14.  *  This program is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *  GNU General Public License for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public License
  20.  *  along with this program; if not, write to the Free Software
  21.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  *
  23.  *  The author can be contacted by s-mail at
  24.  *    Torsten Poulin
  25.  *    Banebrinken 99, 2, 77
  26.  *    DK-2400 Copenhagen NV
  27.  *    DENMARK
  28.  *
  29.  * Created 23-Feb-92 (Version 1)
  30.  * $Id: DirTree.c,v 37.5 93/03/01 12:52:58 Torsten Rel $
  31.  * $Log:    DirTree.c,v $
  32.  * Revision 37.5  93/03/01  12:52:58  Torsten
  33.  * Changed all occurrences of "struct DosBase *" to "struct DosLibrary *"
  34.  * 
  35.  * Revision 37.4  93/02/17  22:33:59  Torsten
  36.  * Fixed Enforcer problems when dealing with the no directories
  37.  * specified case.
  38.  * 
  39.  * Revision 37.3  93/02/17  09:12:25  Torsten
  40.  * DIR/M is not a required argument anymore.
  41.  * Is now aware of links, but will not follow them.
  42.  * It used to think that softlinks (fib_DirEntryType == ST_SOFTLINK)
  43.  * were directories that could be entered.
  44.  * Changed the header text a bit.
  45.  * Does not AllocMem() space for filename in listnodes anymore.
  46.  * Now checks whether AllocDosObject() succeeds.
  47.  * 
  48.  * Revision 37.2  93/02/12  15:15:49  Torsten
  49.  * Now responds to Ctrl-C!!! Major improvement!!!
  50.  * New switch: FILES.
  51.  * 
  52.  */
  53.  
  54. /*
  55.  * The bit-map code in this program was picked up from Dr. Dobb's
  56.  * I think, but I don't remember which volume ;-(
  57.  *
  58.  * Define LOCKALL to ensure that directories being examined
  59.  * don't disappear before we're done with them.
  60.  * The disadvantage is that we use more memory.
  61.  */
  62. #define LOCKALL
  63.  
  64.  
  65.  
  66. #include <exec/types.h>
  67. #include <exec/memory.h>
  68. #include <dos/dos.h>
  69. #include <dos/dosextens.h>
  70. #include <dos/dostags.h>
  71. #include <dos/datetime.h>
  72. #include <dos/dosasl.h>
  73. #include <string.h>
  74.  
  75. #include <proto/exec.h>
  76. #include <proto/dos.h>
  77.  
  78. #include "dirtree_rev.h"
  79.  
  80. /* my include files are for V36, so ... */
  81. #pragma libcall UtilityBase Stricmp A2 9802
  82. LONG Stricmp(char *, char *);
  83.  
  84. #define PROGNAME "DirTree"
  85. #define USERBREAK (-1)
  86. #define BAR "|   "
  87. #define ELL "`---"
  88. #define TEE "+---"
  89.  
  90. struct nameList {
  91.   struct nameList *next;
  92.   char name[108]; /* just to be safe... */
  93.   LONG type;
  94. #ifdef LOCKALL
  95.   BPTR lock;
  96. #endif
  97. };
  98.  
  99. typedef struct {
  100.   struct Library      *SysBase;
  101.   struct DosLibrary   *DOSBase;
  102.   struct Library      *UtilityBase;
  103.  
  104.   BOOL nohead;
  105.   BOOL files;
  106.   char Map[64 / 8];
  107. } Global;
  108.  
  109. char const versionID[] = VERSTAG;
  110. char const copyright[] = "$COPYRIGHT:©1992,1993 Torsten Poulin$";
  111.  
  112. static VOID setbit(Global *global, LONG c, LONG val);
  113. static VOID print_bars(Global *global, LONG depth, LONG terminate);
  114. static LONG printdtree(Global *global, UBYTE *dname, LONG others);
  115. LONG dirtree(Global *global, char *dirname);
  116.  
  117.  
  118. LONG entrypoint(VOID)
  119. {
  120.   struct Library      *SysBase;
  121.   struct DosLibrary   *DOSBase;
  122.   struct Library      *UtilityBase;
  123.   Global *global;
  124.         
  125.   struct RDArgs *args;
  126.   LONG   arg[3];
  127.   LONG   rc = RETURN_OK;
  128.   UBYTE  **dir;
  129.  
  130.   arg[0] = arg[1] = arg[2] = 0L;
  131.     
  132.   SysBase = *(struct Library **) 4L;
  133.     
  134.   if (!(global = AllocMem(sizeof(Global), MEMF_PUBLIC | MEMF_CLEAR)))
  135.     return RETURN_FAIL;
  136.  
  137.   global->SysBase = SysBase;
  138.   if (!(global->DOSBase = DOSBase = (struct DosLibrary *)
  139.     OpenLibrary("dos.library", 37L)))
  140.   {
  141.     rc = RETURN_FAIL;
  142.     goto noDOS;
  143.   }
  144.   if (!(global->UtilityBase = UtilityBase =
  145.     OpenLibrary("utility.library", 37L)))
  146.   {
  147.     rc = RETURN_FAIL;
  148.     goto noUtility;
  149.   }
  150.                                                                         
  151.   if (args = ReadArgs("DIR/M,NOHEAD/S,FILES/S", arg, NULL))
  152.   {
  153.     global->nohead = (BOOL) arg[1];
  154.     global->files = (BOOL) arg[2];
  155.     dir = (UBYTE **) *arg;
  156.     if (dir)
  157.       for (; *dir && rc == RETURN_OK; dir++)
  158.     rc = dirtree(global, *dir);
  159.     else
  160.       rc = dirtree(global, "");
  161.     FreeArgs(args);
  162.   }
  163.   else
  164.   {
  165.     LONG err = IoErr();
  166.     PrintFault(err, PROGNAME);
  167.     rc = RETURN_ERROR;
  168.   }
  169.     
  170.   CloseLibrary(UtilityBase);
  171.  noUtility:
  172.   CloseLibrary((struct Library *) DOSBase);
  173.  noDOS:
  174.   FreeMem(global, sizeof(Global));
  175.   return rc;
  176. }
  177.  
  178.  
  179. #define testbit(x)  ( global->Map[x >> 3] & (1 << (x & 0x07)) )
  180.  
  181. static VOID setbit(Global *global, LONG c, LONG val)
  182. {
  183.   if (val)
  184.     global->Map[c >> 3] |= 1 << (c & 0x07);
  185.   else
  186.     global->Map[c >> 3] &= ~(1 << (c & 0x07));
  187. }
  188.  
  189.  
  190. static VOID print_bars(Global *global, LONG depth, LONG terminate)
  191. {
  192.   struct DosLibrary *DOSBase = global->DOSBase;
  193.   LONG i;
  194.     
  195.   for (i = 0; i < depth - 1; i++)
  196.     PutStr(testbit(i) ? BAR : "    ");
  197.         
  198.   if (terminate)
  199.     PutStr("\n");
  200. }
  201.  
  202.  
  203. static LONG printdtree(Global *global, UBYTE *dname, LONG others)
  204. {
  205.   struct Library    *SysBase      = global->SysBase;
  206.   struct DosLibrary *DOSBase      = global->DOSBase;
  207.   struct Library    *UtilityBase  = global->UtilityBase;
  208.     
  209.   struct FileInfoBlock *m;
  210.   BPTR   lock, oldlock;
  211.   static LONG depth = -1;
  212.   LONG   count = 0;
  213.   LONG   rc = RETURN_OK;
  214.   struct nameList *list, *p;
  215.   struct nameList *newnode;
  216.   LONG   type;
  217.   BOOL   OutOfMemory = FALSE;
  218.   BOOL   UserBreak = FALSE;
  219.  
  220.   list = NULL;
  221.  
  222.   if (!(m = AllocDosObject(DOS_FIB, NULL)))
  223.   {
  224.     PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
  225.     return RETURN_FAIL;
  226.   }
  227.     
  228.   if (lock = Lock(dname, SHARED_LOCK))
  229.   {
  230.     oldlock = CurrentDir(lock);
  231.     if (Examine(lock, m))
  232.     {
  233.       type = m->fib_DirEntryType;
  234.       if (type < 0 || type == ST_SOFTLINK)
  235.       {
  236.     PrintFault(ERROR_OBJECT_WRONG_TYPE, dname);
  237.     CurrentDir(oldlock);
  238.     UnLock(lock);
  239.     FreeDosObject(DOS_FIB, m);
  240.     return RETURN_WARN;
  241.       }
  242.  
  243.       if (++depth)
  244.       {
  245.     print_bars(global, depth, 0);
  246.     PutStr(others ? TEE : ELL);
  247.       }
  248.       PutStr(m->fib_FileName);    /* dir name */
  249.       if (global->files)
  250.     PutStr(" (dir)");
  251.       PutStr("\n");
  252.  
  253.       while (ExNext(lock, m))
  254.       {
  255.     if (UserBreak = (BOOL) CheckSignal(SIGBREAKF_CTRL_C))
  256.       break;
  257.  
  258.     type = m->fib_DirEntryType;
  259.     if (type < 0 && !global->files)
  260.       continue;
  261.  
  262.     /* Store the directory name */
  263.     if (!(newnode = AllocMem(sizeof(struct nameList),
  264.                  MEMF_PUBLIC)))
  265.     {
  266.       PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
  267.       rc = RETURN_FAIL;
  268.       OutOfMemory = TRUE;
  269.       break;
  270.     }
  271.     strcpy(newnode->name, m->fib_FileName);
  272.     newnode->type = type;
  273. #ifdef LOCKALL
  274.     newnode->lock = Lock(m->fib_FileName, SHARED_LOCK);
  275. #endif
  276.     /* Insert */
  277.     newnode->next = NULL;
  278.                 
  279.     if (list == NULL)    /* insert into empty list */
  280.       list = newnode;
  281.     else
  282.     {
  283.       /* inserting into nonempty list */
  284.       p = list;
  285.  
  286.       if (Stricmp(m->fib_FileName, p->name) < 0)
  287.       {
  288.         /* insert before first node */
  289.         newnode->next = list;
  290.         list = newnode;
  291.       }
  292.       else
  293.       {
  294.         /* general case */
  295.         for (; p->next; p = p->next)
  296.           if (Stricmp(m->fib_FileName, p->next->name) < 0)
  297.         break;
  298.         newnode->next = p->next;
  299.         p->next = newnode;
  300.       }
  301.     }
  302.     ++count;
  303.       }
  304.     }
  305.  
  306.     /* Traverse the list and free up memory */
  307.     for (p = list; p; )
  308.     {
  309.       struct nameList *remember;
  310.                 
  311.       remember = p;
  312.       if (!OutOfMemory && !UserBreak)
  313.       {
  314.     if (p->type >= 0 && p->type != ST_LINKDIR && p->type != ST_SOFTLINK)
  315.     {
  316.       --count;
  317.       setbit(global, depth, count);
  318.       rc = printdtree(global, p->name, count);
  319.       if (rc == USERBREAK)
  320.         UserBreak = TRUE;
  321.       if (rc == RETURN_FAIL)
  322.         OutOfMemory = TRUE;
  323.     }
  324.     else if (global->files || p->type == ST_LINKDIR)
  325.     {
  326.       --count;
  327.       print_bars(global, depth + 1, 0);
  328.       PutStr(count ? TEE : ELL);
  329.       PutStr(p->name);
  330.       switch (p->type)
  331.       {
  332.       case ST_SOFTLINK:
  333.         PutStr(" <sl>");
  334.         break;
  335.       case ST_LINKDIR:
  336.         PutStr(" (dir)");
  337.         /* fall through */
  338.       case ST_LINKFILE:
  339.         PutStr(" <hl>");
  340.       }
  341.       PutStr("\n");
  342.     }
  343.       }
  344.       p = p->next;
  345. #ifdef LOCKALL
  346.       UnLock(remember->lock);
  347. #endif
  348.       FreeMem(remember, sizeof(struct nameList));
  349.     }
  350.     CurrentDir(oldlock);
  351.     UnLock(lock);
  352.   }
  353.   else
  354.   {
  355.     LONG err = IoErr();
  356.     PrintFault(err, dname);
  357.     rc = RETURN_ERROR;
  358.   }
  359.   if (!others)
  360.     print_bars(global, depth, 1);
  361.   --depth;
  362.   
  363.   FreeDosObject(DOS_FIB, m);
  364.   if (UserBreak)
  365.     rc = USERBREAK;
  366.   if (OutOfMemory)
  367.     rc = RETURN_FAIL;
  368.   return rc;
  369. }
  370.  
  371.  
  372. LONG dirtree(Global *global, char *dirname)
  373. {
  374.   struct DosLibrary *DOSBase = global->DOSBase;
  375.   LONG rc;
  376.   struct DateTime dt;
  377.   char day[LEN_DATSTRING], date[LEN_DATSTRING];
  378.     
  379.   if (!global->nohead)
  380.   {
  381.     DateStamp(&dt.dat_Stamp);
  382.     dt.dat_Format  = FORMAT_DOS;
  383.     dt.dat_Flags   = NULL;
  384.     dt.dat_StrDay  = day;
  385.     dt.dat_StrDate = date;
  386.     dt.dat_StrTime = NULL;
  387.     DateToStr(&dt);
  388.  
  389.     PutStr("Directory tree \"");
  390.     PutStr(dirname);
  391.     PutStr("\" on ");
  392.     PutStr(day);
  393.     PutStr(" ");
  394.     PutStr(date);
  395.     PutStr("\n\n");
  396.   }
  397.   if ((rc = printdtree(global, dirname, 0)) == USERBREAK)
  398.   {
  399.     PrintFault(ERROR_BREAK, NULL);
  400.     rc = RETURN_WARN;
  401.   }
  402.   return rc;
  403. }
  404.